package com.nercel.dsj.gksales.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.nercel.dsj.gksales.constant.Conf;
import com.nercel.dsj.gksales.dao.mapper.AgentMapper;
import com.nercel.dsj.gksales.exception.ResponseCode;
import com.nercel.dsj.gksales.exception.RestApiException;
import com.nercel.dsj.gksales.model.BalanceRecordType;
import com.nercel.dsj.gksales.model.ListResult;
import com.nercel.dsj.gksales.model.QueryParams;
import com.nercel.dsj.gksales.model.dto.AgentCreateParamsDTO;
import com.nercel.dsj.gksales.model.dto.AgentResultDTO;
import com.nercel.dsj.gksales.model.entity.Agent;
import com.nercel.dsj.gksales.model.entity.BalanceRecord;
import com.nercel.dsj.gksales.model.entity.Region;
import com.nercel.dsj.gksales.model.entity.User;
import com.nercel.dsj.gksales.service.*;
import com.nercel.dsj.gksales.util.Md5Util;
import com.nercel.dsj.gksales.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author sunlin
 * @date 2019-4-12
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AgentServiceImpl implements AgentService {

	private static final Logger logger = LoggerFactory.getLogger(AgentServiceImpl.class);

	private final UserService userService;

	private final AgentMapper agentMapper;

	private final BalanceRecordService balanceRecordService;

	private final RegionService regionService;

	private final SmsService smsService;

	private final ConfigurationService configurationService;

    @Override
    public void save(Agent agent) {
        agentMapper.insertSelective(agent);
    }

    @Override
    public void update(Agent agent) {
        agentMapper.updateByPrimaryKeySelective(agent);
    }

	@Override
    public AgentResultDTO findById(Integer id) {
        QueryParams queryParams = new QueryParams();
        queryParams.put("id", id);
        List<AgentResultDTO> list = agentMapper.query(queryParams);
        return list.size() == 0 ? null : list.get(0);
    }

	@Override
	public AgentResultDTO findByUserId(Integer id) {
		QueryParams queryParams = new QueryParams();
		queryParams.put("userId", id);
		List<AgentResultDTO> list = agentMapper.query(queryParams);
		return list.size() == 0 ? null : list.get(0);
	}

	@Override
    public void delete(Integer id) {
        agentMapper.deleteByPrimaryKey(id);
    }

	@Override
	public void deleteByUserId(Integer id) {
		agentMapper.deleteByUserId(id);
	}

	@Override
    public ListResult<AgentResultDTO> listWithPaging(QueryParams queryParams) {
        Page<AgentResultDTO> page = PageHelper.startPage(queryParams.getPageNumber(), queryParams.getPageSize());
        agentMapper.query(queryParams);
        return new ListResult<>(page);
    }

	@Override
	@Transactional
	public void transfer(Integer srcAgentId, Integer targetAgentId, Integer amount) {
		synchronized(this) {
			AgentResultDTO srcAgent = findByUserId(srcAgentId);
			AgentResultDTO targetAgent = findByUserId(targetAgentId);
			if(srcAgent == null || targetAgent == null){
				throw new RestApiException(ResponseCode.AGENT_NOT_EXIST);
			}
			if(srcAgent.getAmount() < amount){
				throw new RestApiException(ResponseCode.NOT_SUFFICIENT_AMOUNT);
			}
			Agent srcUpdateAgent = new Agent();
			srcUpdateAgent.setId(srcAgent.getAgentId());
			srcUpdateAgent.setAmount(srcAgent.getAmount() - amount);
			this.update(srcUpdateAgent);
			Agent targetUpdateAgent = new Agent();
			targetUpdateAgent.setId(targetAgent.getAgentId());
			targetUpdateAgent.setAmount(targetAgent.getAmount() + amount);
			this.update(targetUpdateAgent);
			logger.info(srcAgent.getPhone() + " 转帐额度 (" + amount + ") " + targetAgent.getPhone());
			BalanceRecord balanceRecord = new BalanceRecord(srcAgentId, targetAgentId,
					srcAgent.getAmount() - amount, targetAgent.getAmount() + amount,
					BalanceRecordType.TRANSFER, amount, new Date(), "转拔额度");
			balanceRecordService.save(balanceRecord);
		}
	}

	@Override
	public Integer increaseAmount(Integer userId, Integer amount) {
		AgentResultDTO agent = findByUserId(userId);
		Agent updateAgent = new Agent();
		updateAgent.setId(agent.getAgentId());
		updateAgent.setAmount(agent.getAmount() + amount);
		this.update(updateAgent);
		logger.info("增加额度 (" + amount + ") " + agent.getPhone());
		return agent.getAmount() + amount;
	}


	@Override
	@Transactional
	public Integer createAgentAccount(AgentCreateParamsDTO agentParamsDTO) {
    	if(agentParamsDTO.getPhone() == null || agentParamsDTO.getRegionId() == null){
			throw new RestApiException(ResponseCode.NO_EXPECTATIONS_ARGUMENT);
		}
		QueryParams queryParams = new QueryParams();
		queryParams.put("phone", agentParamsDTO.getPhone());
		if(agentMapper.query(queryParams).size() > 0){
			throw new RestApiException(ResponseCode.AGENT_EXIST);
		}
		User user = userService.findByPhone(agentParamsDTO.getPhone());
		if(user == null){
			if(agentParamsDTO.getPassword() == null){
				throw new RestApiException(ResponseCode.NO_EXPECTATIONS_ARGUMENT);
			}
			user = new User();
			user.setPhone(agentParamsDTO.getPhone());
			String salt = StringUtil.randomUUID().substring(0, 6);
			String password = Md5Util.getMD5String(salt + agentParamsDTO.getPassword());
			user.setPassword(password);
			user.setSalt(salt);
			userService.save(user);
		}
		Agent agent = new Agent();
		agent.setUserId(user.getId());
		agent.setChannel("UNICOM");
		agent.setCreateTime(new Date());
		agent.setRegionId(agentParamsDTO.getRegionId());
		agent.setRemark(agentParamsDTO.getRemark());
		this.save(agent);
		sendSmsToParentAgents(agent.getRegionId(), agentParamsDTO.getPhone());
		return user.getId();
	}

	private List<AgentResultDTO> getParentAgents(Integer parentRegionId){
		QueryParams queryParams = new QueryParams();
		queryParams.put("regionId", parentRegionId);
		return agentMapper.query(queryParams);
	}

	/**
	 * 发送通知短信
	 * @param regionId
	 * @param agentPhone
	 */
	private void sendSmsToParentAgents(Integer regionId, String agentPhone){
		Region region = regionService.findById(regionId);
		Integer parentRegionId = region.getParentId();
		if(parentRegionId == 1){
			String userIds = configurationService.getConfigurationByName(Conf.AGENT_ADMIN_USER_IDS).getValue();
			QueryParams queryParams = new QueryParams();
			queryParams.put("ids", userIds.split(","));
			ListResult<User> users = userService.listWithPaging(queryParams);
			if(users.getTotal() < 5){
				users.getData().forEach(user->{
					smsService.sendAgentRegisteredMessage(user.getPhone(), agentPhone);
				});
			}
		}else{
			List<AgentResultDTO> parentAgents = getParentAgents(parentRegionId);
			if(parentAgents.size() < 5) {
				parentAgents.forEach((agent) -> {
					smsService.sendAgentRegisteredMessage(agent.getPhone(), agentPhone);
				});
			}
		}
	}

	@Override
	public List<Map<String, Object>> statistics(QueryParams params) {
		return agentMapper.statistics(params);
	}

}
